package  com.designoutput.ui.controls
{
	import com.designoutput.enum.Direction;
	import com.designoutput.event.RulerEvent;
	import com.designoutput.ui.CardFaceEditor;
	import com.designoutput.ui.controls.rulerComp.GuideLine;
	import com.designoutput.utils.Globals;
	import com.designoutput.utils.Unit;
	
	import flash.display.Sprite;
	import flash.events.ContextMenuEvent;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.ui.ContextMenu;
	import flash.ui.ContextMenuItem;
	import flash.utils.Dictionary;
	
	public class Ruler extends Sprite
	{		
		private var p:CardFaceEditor;
		
		private var _horizontalOffset:Number = 0;
		private var _verticalOffset:Number = 0;
		
		private var _unit:Unit = Unit.INCHES;		
		
		private var _rulerContainer:Sprite;
		private var _horizontalTracker:Sprite;
		private var _verticalTracker:Sprite;
		
		private var _rulerWidth:Number;
		private var _rulerHeight:Number;

		private var _textFieldArray:Vector.<TextField>;
		
		private var _availableUnits:Vector.<Unit> = new <Unit>[ Unit.PIXELS, Unit.INCHES, Unit.CENTIMETERS, Unit.MILLIMETERS, Unit.POINTS, Unit.PICAS ];
		private var _rulerMenu:Sprite;
		private var _rulerContextMenu:ContextMenu;
		private var _unitByContextMenuItem:Dictionary;

		private var _fixedRulerWidth:Number = 10;
		private var _previousUnit:Unit = Unit.INCHES;
		
		private var _unitNum:Number; // lenght or width for a single unit 
		public var scale:Number = 1;
		private var _unitA:Array;
		private var _nextRulerText:Number;
		private var _rulerIncrement:Number;
		private var _ppi:Number = 96;
		
		public  function Ruler(parent:CardFaceEditor){
			this.p = parent;
			
			createMenu();
			createContextMenu();
		}
		
		public function get unitNum():Number
		{
			return _unitNum;
		}

		public function setParameters(horizontalWidth:Number, verticalHeight:Number, _indentX:Number = 14, _indentY:Number = 14):void{
			_horizontalOffset = Math.round(_indentX) + 2;
			_verticalOffset = Math.round(_indentY) + 2;
			
			_textFieldArray = new Vector.<TextField>();
			_rulerWidth = horizontalWidth ;
			_rulerHeight = verticalHeight;
			drawRuler(_rulerWidth, _rulerHeight);
		}
		
		/**
		 * Change the ruler's scale when zoom canvas.
		 * @param scale - Number value
		 */		
		public function setScale(scale:Number):void{
			this.scale = scale;
		}
		
		public function drawRuler(w:Number, h:Number):void{
			if(_rulerContainer!=null){
				for each(var txt:TextField in _textFieldArray){
					if(_rulerContainer.contains(txt)){
						_rulerContainer.removeChild(txt);
						txt = null;
					}
				}
				if(this.contains(_rulerContainer)){
					this.removeChild(_rulerContainer);
				}
				_textFieldArray = new Vector.<TextField>();
			}
			_rulerContainer = new Sprite();
			
			this.addChild(_rulerContainer);
			
			_rulerContainer.addEventListener(MouseEvent.MOUSE_DOWN, rulerMouseDown, false, 0, true);
			_rulerContainer.addEventListener(MouseEvent.CLICK, clickHandler, false, 0, true);
			
			this.mouseTracker();
			
			this.contextMenu =  _rulerContextMenu;
			
			
			this.reDrawRuler(w,h);
		}
		
		private function tr():void{
			for(var i:int =0 ;i<this.numChildren;i++){
				trace(this.getChildAt(i));
			}
		}
		
		
		
		
		/****************** handle events ************************/
		
		/**
		 * The guide line array pool. When there is available exist lines, just use them, no need create new ones
		 * @private
		 */		
		private var guideLineArr:Array = [];
		
		/**
		 * Called when mouse down on ruler. It will show GuideLine.
		 * @param evt - MouseEvent
		 */		
		private function rulerMouseDown(evt:MouseEvent):void{
			trace("rulerMouseDown");
			
			var line:GuideLine;
			var existLineNum:int = this.guideLineArr.length;
			for(var i:int =0;i<existLineNum;i++){
				var existLine:GuideLine = this.guideLineArr[i] as GuideLine;
				if(existLine){
					if(existLine.visible == false){
						line = existLine;
						line.visible = true;
						break;
					}
				}
			}
			if(!line){
				line = new GuideLine(this);
			}
			if(_rulerContainer.mouseY<_fixedRulerWidth){
				line.orientation = Direction.Horizontal;
				line.x = 0;
				line.y = _rulerContainer.mouseY-3;
			}else if(_rulerContainer.mouseX<_fixedRulerWidth){
				line.orientation = Direction.Vertical;
				line.x = _rulerContainer.mouseX-3;
				line.y = 0;
			}
			this.addChild(line);
			line.lineDown(null);
			guideLineArr.push(line);
			
		}
		
		private function clickHandler(evt:MouseEvent):void{
			if(_rulerContainer.mouseX >= 0 && _rulerContainer.mouseX<=_fixedRulerWidth || _rulerContainer.mouseY >= 0 && _rulerContainer.mouseY<=_fixedRulerWidth){
				Globals.popupManager.addPopup(_rulerMenu, false);
				_rulerMenu.addEventListener(MouseEvent.ROLL_OUT, hideRulerMenu, false, 0, true);
				_rulerMenu.x = stage.mouseX - 10;
				_rulerMenu.y = stage.mouseY - 10;
			}
			
		}
		
		
		
		/***************************** red tracker*******************************/
		/**
		 * Move the red tracker when mouse move on Canvas
		 * 
		 */		
		public function mouseTracker():void{
			createTracker();
			this.p.addEventListener(MouseEvent.MOUSE_MOVE, trackerMoveHandler, false, 0, true);
			
		}
		
		public function trackerMoveHandler(evt:MouseEvent):void{
			if(this.p.mouseY>=_verticalOffset){
				if(this.p.mouseY - 22<=16){
					_verticalTracker.y  = 16;
				}else{
					_verticalTracker.y = this.p.mouseY - 22;
				}
			}
			if(this.p.mouseX>=_horizontalOffset){
				if(this.p.mouseX - 3<=16){
					_horizontalTracker.x  = 16;
				}else{
					_horizontalTracker.x = this.p.mouseX - 3;
				}
			}
		}
		
		public function createTracker():void{
			if(_verticalTracker && _horizontalTracker){
				if(_rulerContainer.contains(_verticalTracker)){
					_rulerContainer.removeChild(_verticalTracker);
				}
				if(_rulerContainer.contains(_horizontalTracker)){
					_rulerContainer.removeChild(_horizontalTracker);
				}
			}
			_verticalTracker = new Sprite();
			_rulerContainer.addChild(_verticalTracker);
			_horizontalTracker = new Sprite();
			_rulerContainer.addChild(_horizontalTracker);
			
			_verticalTracker.graphics.clear();
			_verticalTracker.graphics.lineStyle(0,0xff0000);
			for(var i:int=0;i<_fixedRulerWidth;i++){
				_verticalTracker.graphics.moveTo(i,0);
				_verticalTracker.graphics.lineTo(i+1,0);
			}
			
			_horizontalTracker.graphics.clear();
			_horizontalTracker.graphics.lineStyle(0,0xff0000);
			for(i=0;i<_fixedRulerWidth;i++){
				_horizontalTracker.graphics.moveTo(0,i);
				_horizontalTracker.graphics.lineTo(0,i+1);
			}
		}
		
		/****************** click on the ruler, pop up the rule unit list************************/
		
		private function createMenu():void{
			_rulerMenu = new Sprite;
			_rulerMenu.graphics.beginFill(0x928e04,1);
			_rulerMenu.graphics.drawRoundRect(1,1,90,140,3);
			_rulerMenu.graphics.beginFill(0xdcdbb1,0.7);
			_rulerMenu.graphics.drawRoundRect(0,0,90,140,3);
			_rulerMenu.graphics.endFill();
			
			for(var i:int = 0;i<_availableUnits.length;i++){
				var unit:Unit = _availableUnits[i];
				var sel:SelectItem = new SelectItem(unit.name, unit.name, 80);
				sel.y = i*22+8;
				sel.x = 5;
				sel.addEventListener(MouseEvent.MOUSE_DOWN, unitItemClickHandler, false, 0, true);
				_rulerMenu.addChild(sel);
			}
		}
			
		private function hideRulerMenu(evt:MouseEvent):void {
			_rulerMenu.removeEventListener(MouseEvent.ROLL_OUT, hideRulerMenu, false);
			
			Globals.popupManager.removePopup(_rulerMenu);
		}
		
		private function unitItemClickHandler(evt:MouseEvent):void{
			var elem:SelectItem = evt.currentTarget as SelectItem;
			
			if(elem)
				setUnit(Unit.getUnitByName(elem.text));

			hideRulerMenu(null);
		}
		
		public function setUnit(unit:Unit):void {
			if(_unit != unit){
				_unit = unit;
				drawRuler(_rulerWidth, _rulerHeight);
			}
		}
		
		/**************************** context menu when right click *************************************/
		public function createContextMenu():void {
			_unitByContextMenuItem = new Dictionary();
			
			_rulerContextMenu = new ContextMenu();
			_rulerContextMenu.hideBuiltInItems();
			
			for each(var unit:Unit in _availableUnits){
				var contextMenuItem:ContextMenuItem = new ContextMenuItem(unit.name);
				contextMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenu_itemSelectHandler, false, 0, true);
				_rulerContextMenu.customItems.push(contextMenuItem);
				
				_unitByContextMenuItem[contextMenuItem] = unit;
			}
		}
		
		public function contextMenu_itemSelectHandler(evt:ContextMenuEvent):void{
			var selectedUnit:Unit = _unitByContextMenuItem[evt.target];
			
			_unit = selectedUnit;
			drawRuler(_rulerWidth, _rulerHeight);
		}
		
		/********************************* draw ruler ********************************/
		private function reDrawRuler(w:Number, h:Number):void{
			_rulerContainer.graphics.clear();
			_rulerContainer.graphics.lineStyle(0,0);
			_rulerContainer.graphics.moveTo(_fixedRulerWidth,0);
			_rulerContainer.graphics.lineTo(w,0);
			_rulerContainer.graphics.moveTo(0,_fixedRulerWidth);
			_rulerContainer.graphics.lineTo(w,_fixedRulerWidth);
			
			_rulerContainer.graphics.moveTo(0,_fixedRulerWidth);
			_rulerContainer.graphics.lineTo(0,h);
			_rulerContainer.graphics.moveTo(_fixedRulerWidth,0);
			_rulerContainer.graphics.lineTo(_fixedRulerWidth,h);
			
			var rulerTxt:TextField;
			var rulerTxtFmt:TextFormat = new TextFormat();
			rulerTxtFmt.size = 9;
			rulerTxtFmt.color = 0;
			rulerTxtFmt.align = TextFormatAlign.LEFT;
			
			unitF();
			for(var i:uint=0;i<w/unitNum;i++){
				var x:Number = i*unitNum+_horizontalOffset;
				for(var j:uint=0;j<_unitA.length;j++){
					if(i%_unitA[j][0]==0){
						_rulerContainer.graphics.moveTo(x,_fixedRulerWidth);
						_rulerContainer.graphics.lineTo(x,_fixedRulerWidth-_unitA[j][1]);
						if(j==0){
							rulerTxt = new TextField();
							rulerTxt.backgroundColor = 0xFF0000;
							rulerTxt.x = x;
							rulerTxt.y = -4;
							rulerTxt.defaultTextFormat = rulerTxtFmt;
							rulerTxt.height = 14;
							rulerTxt.selectable = false;
							rulerTxt.multiline = false;
							rulerTxt.text = _nextRulerText.toString();
							/**Just set a enough large number, so the unit list could shown any time*/
							rulerTxt.width = 1000; 
							_textFieldArray.push(rulerTxt);
							_rulerContainer.addChild(rulerTxt);
							_nextRulerText += _rulerIncrement;
						}
						break;
					}
				}
			}
			
			/**Reset the rulerIncrement*/
			unitF();
			
			for(i=0;i<h/unitNum;i++){
				var y:Number = i*unitNum+_verticalOffset;
				for(j=0;j<_unitA.length;j++){
					if(i%_unitA[j][0]==0){
						_rulerContainer.graphics.moveTo(_fixedRulerWidth,y);
						_rulerContainer.graphics.lineTo(_fixedRulerWidth-_unitA[j][1],y);
						if(j==0){
							rulerTxt = new TextField();
							rulerTxt.defaultTextFormat = rulerTxtFmt;
							rulerTxt.width = 14;
							rulerTxt.x = 0;
							rulerTxt.y = y - 3;
							rulerTxt.selectable = false;
							rulerTxt.multiline = true;
							rulerTxt.text = _nextRulerText.toString().split("").join("\n");
							_rulerContainer.addChild(rulerTxt);
							_textFieldArray.push(rulerTxt);
							_nextRulerText += _rulerIncrement;
						}
						break;
					}
				}
			}
			
			this.rePositionGuideLines();
			
			/**Dispatch RulerUnitChangeEvent, to notify the canvas, will change the unit information. 
			 * Monitor this event in Canvas(rulerUnitChangeHandler method)*/
			if(_previousUnit != _unit){
				this.dispatchEvent(new RulerEvent(_unit));
			}
			_previousUnit = _unit;
		}
		
		/**
		 * Re-position visible guide lines while zoom on canvas.
		 */		
		private function rePositionGuideLines():void{
			for(var i:int = 0; i < guideLineArr.length; i++){
				var line:GuideLine = guideLineArr[i] as GuideLine;
				if(line.visible){
					if(line.isVertical){
						if(_unit==_previousUnit){
							/**16, is the distance of the card from the canvas X scale 0 point.*/
							line.x = line.calibration*this.unitNum + 16;
						}
					}else{
						if(_unit==_previousUnit){
							line.y = line.calibration*this.unitNum + 16;
						}
					}
				}
			}
		}
		
		public function unitF():void{
			if(_unit == Unit.PIXELS){
				_unitNum = Math.round(5*this.scale*10)/10;
				_unitA = [[10,_fixedRulerWidth],[2,_fixedRulerWidth/4],[1,_fixedRulerWidth/8]];
				_nextRulerText = 0;
				_rulerIncrement = 50;
			} else if(_unit == Unit.INCHES){
				_unitNum = Math.round(10*this.scale*_ppi/16)/10;
				_unitA = [[16,_fixedRulerWidth],[8,_fixedRulerWidth/2],[4,_fixedRulerWidth/4],[2,_fixedRulerWidth/8],[1,_fixedRulerWidth/16]];
				_nextRulerText = 0;
				_rulerIncrement = 1;
			} else if(_unit == Unit.CENTIMETERS){
				_unitNum = Math.round(10*8*this.scale)/10;
				_unitA = [[5,_fixedRulerWidth],[1,_fixedRulerWidth/4]];
				_nextRulerText = 0;
				_rulerIncrement = 1;
			}
			else if(_unit == Unit.MILLIMETERS){
				_unitNum = Math.round(10*8*this.scale)/10;
				_unitA = [[5,_fixedRulerWidth],[1,_fixedRulerWidth/4]];
				_nextRulerText = 0;
				_rulerIncrement = 10;
			}
			else if(_unit == Unit.POINTS){
				_unitNum = Math.round(10*8*this.scale)/10;
				_unitA = [[6,_fixedRulerWidth],[1,_fixedRulerWidth/4]];
				_nextRulerText = 0;
				_rulerIncrement = 36;
			}
			else if(_unit == Unit.PICAS){
				_unitNum = Math.round(10*8*this.scale)/10;
				_unitA = [[6,_fixedRulerWidth],[1,_fixedRulerWidth/4]];
				_nextRulerText = 0;
				_rulerIncrement = 3;
			}
		}
	}
	
}